package com.jinbei.security;

import com.jinbei.common.annotation.EncryptMethod;
import com.jinbei.common.contants.Contants;
import com.jinbei.common.util.AesUtil;
import com.jinbei.filter.XssFilter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * @author zflu
 * 解密request json
 * 使用 aes解密
 * Created by lucky on 2018/8/23.
 */
//@ControllerAdvice
public class EncryptRequestBodyAdvice extends XssFilter implements RequestBodyAdvice {

    private final Logger logger = LoggerFactory.getLogger(EncryptRequestBodyAdvice.class);

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        try {
            Method method = parameter.getMethod();
            //是否使用加密注解
            if(method.isAnnotationPresent(EncryptMethod.class)){
                EncryptMethod annotation = method.getAnnotation(EncryptMethod.class);
                //如果加密为开启 true
                boolean encrypt = annotation.isEncrypt();
                if(encrypt){
                    return new EncryptHttpInputMessage(inputMessage);
                }else{
                    return inputMessage;
                }
            }else{
                return inputMessage;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("RequestBody 解密失败！ error :",e);
            return inputMessage;
        }
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    class EncryptHttpInputMessage implements HttpInputMessage {

        private HttpHeaders httpHeaders;

        private InputStream body;

        public EncryptHttpInputMessage(HttpInputMessage inputMessage) throws Exception{
            this.httpHeaders = inputMessage.getHeaders();
            this.body = inputMessage.getBody();
        }

        @Override
        public InputStream getBody() throws IOException {
            if(StringUtils.isBlank(ENCRYPT_KEY.get())){
                body =  IOUtils.toInputStream(AesUtil.decrypt(IOUtils.toString(body, Contants.CHARSET_NAME)),Contants.CHARSET_NAME);
            }else{
                body =  IOUtils.toInputStream(AesUtil.decrypt(IOUtils.toString(body, Contants.CHARSET_NAME),ENCRYPT_KEY.get(),null),Contants.CHARSET_NAME);
            }
            return body;
        }

        @Override
        public HttpHeaders getHeaders() {
            return httpHeaders;
        }
    }
}
